﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Application.Core.Entities;
using Application.Core.Interfaces;
using NPoco;
using NPoco.Expressions;
using NPoco.Linq;

namespace Infrastructure.Data
{
    /// <summary>
    /// 仓储默认实现
    /// </summary>
    /// <typeparam name="TEntity">实体类型</typeparam>
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : BaseEntity
    {
        public ILogger Logger { get; set; }
        public IDatabase Logger { get; set; }
        
        public Repository()
        {
            Logger = NullLogger.Instance;
        }

        private IDatabase _db;

        /// <summary>
        /// 获取数据操作上下文
        /// </summary>
        /// <returns></returns>
        public IDatabase DbContext
        {
            get
            {
                //if (_db == null)
                    _db = new Database(DbConfig.Default);
                return _db;
            }
            set { _db = value; }
        }

        /// <summary>
        /// 插入实体
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <returns>主键</returns>
        public virtual object Insert(TEntity entity)
        {
            return DbContext.Insert(entity);
        }

        /// <summary>
        /// 异步插入实体
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <returns>主键</returns>
        public virtual async Task<object> InsertAsync(TEntity entity)
        {
            return await DbContext.InsertAsync(entity);
        }

        /// <summary>
        /// 更新实体
        /// </summary>
        /// <param name="entity">实体对象</param>
        public virtual void Update(TEntity entity)
        {
            DbContext.Update(entity);
        }

        /// <summary>
        /// 异步更新实体
        /// </summary>
        /// <param name="entity">实体对象</param>
        public virtual async Task<int> UpdateAsync(TEntity entity)
        {
            return await DbContext.UpdateAsync(entity);
        }

        /// <summary>
        /// 根据主键删除
        /// </summary>
        /// <param name="primaryKey">主键</param>
        /// <returns>删除的数量</returns>
        public virtual int Delete(object primaryKey)
        {
            return DbContext.Delete<TEntity>(primaryKey);
        }

        /// <summary>
        /// 异步根据实体删除
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <returns>删除的数量</returns>
        public virtual async Task<int> DeleteAsync(TEntity entity)
        {
            return await DbContext.DeleteAsync(entity);
        }

        /// <summary>
        /// 根据实体删除
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <returns>删除的数量</returns>
        public virtual int Delete(TEntity entity)
        {
            return DbContext.Delete(entity);
        }

        /// <summary>
        /// 根据主键判断是否存在
        /// </summary>
        /// <param name="primaryKey">主键</param>
        /// <returns></returns>
        public virtual bool Exists(object primaryKey)
        {
            return DbContext.Exists<TEntity>(primaryKey);
        }

        /// <summary>
        /// 获取单条
        /// </summary>
        /// <param name="primaryKey">主键</param>
        /// <returns>实体对象</returns>
        public virtual TEntity Single(object primaryKey)
        {
            return DbContext.SingleById<TEntity>(primaryKey);
        }

        /// <summary>
        /// 异步获取单条
        /// </summary>
        /// <param name="primaryKey">主键</param>
        /// <returns>实体对象</returns>
        public virtual async Task<TEntity> SingleAsync(object primaryKey)
        {
            return await DbContext.SingleByIdAsync<TEntity>(primaryKey);
        }

        /// <summary>
        /// 获取单条或默认第一条
        /// </summary>
        /// <param name="primaryKey">主键</param>
        /// <returns>实体对象</returns>
        public virtual TEntity SingleOrDefault(object primaryKey)
        {
            return DbContext.SingleOrDefaultById<TEntity>(primaryKey);
        }

        /// <summary>
        /// 异步获取单条或默认第一条
        /// </summary>
        /// <param name="primaryKey">主键</param>
        /// <returns>实体对象</returns>
        public virtual async Task<TEntity> SingleOrDefaultAsync(object primaryKey)
        {
            return await DbContext.SingleOrDefaultByIdAsync<TEntity>(primaryKey);
        }

        /// <summary>
        /// 获取所有的数据，仅用于数据量非常少的情况下
        /// </summary>
        /// <returns>实体集合</returns>
        public virtual IEnumerable<TEntity> GetAll()
        {
            Sql sql = Sql.Builder.Select("*").From(TableInfo.FromPoco(typeof(TEntity)).TableName);
            return DbContext.Query<TEntity>(sql);
        }

        /// <summary>
        /// 异步获取所有的数据，仅用于数据量非常少的情况下
        /// </summary>
        /// <returns>实体集合</returns>
        public virtual async Task<IEnumerable<TEntity>> GetAllAsync()
        {
            Sql sql = Sql.Builder.Select("*").From(TableInfo.FromPoco(typeof(TEntity)).TableName);
            return await DbContext.QueryAsync<TEntity>(sql);
        }

        /// <summary>
        /// 获取所有的数据并排序，仅用于数据量非常少的情况下
        /// </summary>
        /// <param name="orderBy">排序条件</param>
        /// <returns>实体集合</returns>
        public virtual IEnumerable<TEntity> GetAll(string orderBy)
        {
            Sql sql = Sql.Builder.Select("*").From(TableInfo.FromPoco(typeof(TEntity)).TableName);
            if (!string.IsNullOrEmpty(orderBy))
            {
                sql.OrderBy(orderBy);
            }
            return DbContext.Query<TEntity>(sql);
        }
        
        /// <summary>
        /// 异步获取所有的数据并排序，仅用于数据量非常少的情况下
        /// </summary>
        /// <param name="orderBy">排序条件</param>
        /// <returns>实体集合</returns>
        public virtual async Task<IEnumerable<TEntity>> GetAllAsync(string orderBy)
        {
            Sql sql = Sql.Builder.Select("*").From(TableInfo.FromPoco(typeof(TEntity)).TableName);
            if (!string.IsNullOrEmpty(orderBy))
            {
                sql.OrderBy(orderBy);
            }
            return await DbContext.QueryAsync<TEntity>(sql);
        }

        /// <summary>
        /// 获取指定的前某条数据
        /// </summary>
        /// <param name="topNumber">数量</param>
        /// <returns>实体集合</returns>
        public virtual IEnumerable<TEntity> GetTop(int topNumber)
        {
            Sql sql = Sql.Builder.Select("top " + topNumber + " *").From(TableInfo.FromPoco(typeof(TEntity)).TableName);
            return DbContext.Query<TEntity>(sql);
        }
        
        /// <summary>
        /// 异步获取指定的前某条数据
        /// </summary>
        /// <param name="topNumber">数量</param>
        /// <returns>实体集合</returns>
        public virtual async Task<IEnumerable<TEntity>> GetTopAsync(int topNumber)
        {
            Sql sql = Sql.Builder.Select("top " + topNumber + " *").From(TableInfo.FromPoco(typeof(TEntity)).TableName);
            return await DbContext.QueryAsync<TEntity>(sql);
        }

        /// <summary>
        /// 获取排序后的指定前某条数据
        /// </summary>
        /// <param name="topNumber">数量</param>
        /// <param name="orderBy">排序条件</param>
        /// <returns>实体集合</returns>
        public virtual IEnumerable<TEntity> GetTop(int topNumber,string orderBy)
        {
            Sql sql = Sql.Builder.Select("top "+topNumber+" *").From(TableInfo.FromPoco(typeof(TEntity)).TableName);
            if (!string.IsNullOrEmpty(orderBy))
            {
                sql.OrderBy(orderBy);
            }
            return DbContext.Query<TEntity>(sql);
        }

        /// <summary>
        /// 异步获取排序后的指定前某条数据
        /// </summary>
        /// <param name="topNumber">数量</param>
        /// <param name="orderBy">排序条件</param>
        /// <returns>实体集合</returns>
        public virtual async Task<IEnumerable<TEntity>> GetTopAsync(int topNumber, string orderBy)
        {
            Sql sql = Sql.Builder.Select("top " + topNumber + " *").From(TableInfo.FromPoco(typeof(TEntity)).TableName);
            if (!string.IsNullOrEmpty(orderBy))
            {
                sql.OrderBy(orderBy);
            }
            return await DbContext.QueryAsync<TEntity>(sql);
        }

        /// <summary>
        /// 分页获取数据
        /// </summary>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <returns>分页数据对象</returns>
        public virtual Page<TEntity> GetPage(long pageIndex, long pageSize)
        {
            Sql sql = Sql.Builder.Select("*").From(TableInfo.FromPoco(typeof(TEntity)).TableName);
            return DbContext.Page<TEntity>(pageIndex,pageSize,sql);
        }
        
        /// <summary>
        /// 异步分页获取数据
        /// </summary>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <returns>分页数据对象</returns>
        public virtual async Task<Page<TEntity>> GetPageAsync(long pageIndex, long pageSize)
        {
            Sql sql = Sql.Builder.Select("*").From(TableInfo.FromPoco(typeof(TEntity)).TableName);
            return await DbContext.PageAsync<TEntity>(pageIndex,pageSize,sql);
        }

        /// <summary>
        /// 分页获取数据
        /// </summary>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="orderBy">排序条件</param>
        /// <returns>分页数据对象</returns>
        public virtual Page<TEntity> GetPage(long pageIndex, long pageSize, string orderBy)
        {
            Sql sql = Sql.Builder.Select("*").From(TableInfo.FromPoco(typeof(TEntity)).TableName);
            if (!string.IsNullOrEmpty(orderBy))
            {
                sql.OrderBy(orderBy);
            }
            return DbContext.Page<TEntity>(pageIndex, pageSize, sql);
        }
        
        /// <summary>
        /// 异步分页获取数据
        /// </summary>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="orderBy">排序条件</param>
        /// <returns>分页数据对象</returns>
        public virtual async Task<Page<TEntity>> GetPageAsync(long pageIndex, long pageSize, string orderBy)
        {
            Sql sql = Sql.Builder.Select("*").From(TableInfo.FromPoco(typeof(TEntity)).TableName);
            if (!string.IsNullOrEmpty(orderBy))
            {
                sql.OrderBy(orderBy);
            }
            return await DbContext.PageAsync<TEntity>(pageIndex, pageSize, sql);
        }

        /// <summary>
        /// 分页获取数据
        /// </summary>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="sql"></param>
        /// <returns>分页数据对象</returns>
        public virtual Page<TEntity> GetPage(long pageIndex, long pageSize,Sql sql)
        {
            return DbContext.Page<TEntity>(pageIndex, pageSize, sql);
        }
        
        /// <summary>
        /// 异步分页获取数据
        /// </summary>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="sql"></param>
        /// <returns>分页数据对象</returns>
        public virtual async Task<Page<TEntity>> GetPageAsync(long pageIndex, long pageSize, Sql sql)
        {
            return await DbContext.PageAsync<TEntity>(pageIndex, pageSize, sql);
        }

        
        /// <summary>
        /// 根据主键的数组查询
        /// </summary>
        /// <typeparam name="T">主键类型</typeparam>
        /// <param name="entityIds">主键数组</param>
        /// <returns>实体集合</returns>
        public virtual IEnumerable<TEntity> GetByIds<T>(IEnumerable<T> entityIds)
        {
            Sql sql = Sql.Builder.Select("*").From(TableInfo.FromPoco(typeof(TEntity)).TableName);
            if (entityIds.Any())
            {
                sql.Where(TableInfo.FromPoco(typeof(TEntity)).PrimaryKey + " in (@ids)", new { ids = entityIds });
            }
            return DbContext.Query<TEntity>(sql);
        }

        /// <summary>
        /// 异步根据主键的数组查询
        /// </summary>
        /// <typeparam name="T">主键类型</typeparam>
        /// <param name="entityIds">主键数组</param>
        /// <returns>实体集合</returns>
        public virtual async Task<IEnumerable<TEntity>> GetByIdsAsync<T>(IEnumerable<T> entityIds)
        {
            Sql sql = Sql.Builder.Select("*").From(TableInfo.FromPoco(typeof(TEntity)).TableName);
            if (entityIds.Any())
            {
                sql.Where(TableInfo.FromPoco(typeof(TEntity)).PrimaryKey + " in (@ids)", new { ids = entityIds });
            }
            return await DbContext.QueryAsync<TEntity>(sql);
        }

        /// <summary>
        /// 通用查询接口
        /// </summary>
        /// <typeparam name="TEntity">类型</typeparam>
        /// <param name="sql">SQL查询对象</param>
        /// <returns>实体集合</returns>
        public virtual IEnumerable<TEntity> Query(Sql sql)
        {
            return DbContext.Query<TEntity>(sql);
        }

        /// <summary>
        /// 异步通用查询接口
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="sql">SQL查询对象</param>
        /// <returns>实体集合</returns>
        public virtual async Task<IEnumerable<TEntity>> QueryAsync(Sql sql)
        {
            return await DbContext.QueryAsync<TEntity>(sql);
        }

        /// <summary>
        /// Linq多条删除
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <returns>删除的Linq查询</returns>
        public virtual IDeleteQueryProvider<TEntity> DeleteMany()
        {
            return DbContext.DeleteMany<TEntity>();
        }

        /// <summary>
        /// Linq多条更新
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <returns>更新的Linq查询</returns>
        public virtual IUpdateQueryProvider<TEntity> UpdateMany()
        {
            return DbContext.UpdateMany<TEntity>();
        }

        /// <summary>
        /// Linq延迟查询
        /// </summary>
        /// <typeparam name="TEntity">类型</typeparam>
        /// <returns>Linq查询</returns>
        public virtual IQueryProviderWithIncludes<TEntity> Query()
        {
            return DbContext.Query<TEntity>();
        }
        
    }
}
